// 属性描述符   value writable
// 存取描述符   get  set
// 通用描述符   configurable  enumerable
Object.defineProperty(obj, "name", {
  value: "张三", // 默认 undfined
  writable: true, // 默认 false   属性是否可以更改
  enumerable: false, // 默认 false   是否可以枚举，就是能否使用for in/of
  configurable: false, // 默认 false   属性是否可以删除， 其他属性是否可以更改
});
// 对象不能使用of遍历，因为没有iterator结构，也可以使用 Obejct.keys/values/entries 等方法， 前提条件一定要 开启 enumerable 属性
for (var key of Object.entries(obj)) {
  // console.log(key);
}

// 输入 1-10 显示少年   2-20 显示青少年  输入 20-50 显示中年

function Person() {
  let age;
  Object.defineProperty(this, "age", {
    configurable: true,
    get() {
      let ageRange = [10, 20, 50, 90];
      let strMeg = ["少年", "青年", "中年", "老年"];
      for (var i = 0; i < ageRange.length; i++) {
        if (age < ageRange[i]) {
          return strMeg[i];
        }
      }
      // 这个代码及其的不好，通过数组优化，后期方便扩展
      // if (age > 0 && age <= 10) {
      //   return "少年";
      // } else if (age > 10 && age <= 20) {
      //   return "青少年";
      // } else {
      //   return "中年";
      // }
    },
    set(val) {
      age = val;
    },
  });
}

// 迭代器
// 迭代器 iterator
// 必须有一个 Symbol.iterator 方法, 返回一个可迭代对象
// 调用这个方法返回一个 含有next函数的对象，
// 调用next返回 {value: xx, done: true/false} 对象
// 改进版， 让obj对象自身作为迭代器
// for of 是专门给迭代器对象消费的，
let o1 = {
  from: 1,
  to: 5,
  [Symbol.iterator]: function () {
    this.curr = this.from;
    // 这个this指向的是 o自己
    return this;
  },
  next() {
    if (this.curr <= this.to) {
      // 通过 this.current 记忆了当前的迭代进程
      return { value: this.curr++, done: false };
    } else {
      return { done: true };
    }
  },
};

// ------------------vue数组变异方法
// 那么怎么样拦截数组原生的方法呢
// 根据原型链的查找机制
// arr.__proto__ === Array.prototype
// 在进行arr.push的时候，如果对象上找不到push方法，就会项原型链上面查找；所以在向上查找的时候，给他们中间添加一个中间层 arrayMethods,这个时候原型链的查找机制就变为了
// arr.__proto__ === arrayMethods.__proto__ === Array.protottype
// 根据原型链的查找规则，会先在arrayMethods对象中查找， 这样，我们就实现了对数组变异方法的拦截
// arrayMethods继承数组的原型对象，即arrayMethods.__proto__ = Array.prototype
// const arrayMethods = Object.create(Array.prototype)

// 数组的变异方法
const variationMethods = [
  "splice",
  "sort",
  "push",
  "pop",
  "reverse",
  "shift",
  "unshift",
];
// 缓存数组的原型对象
const tmpArrayPrototype = Array.prototype;
// middLayer继承数组的原型对象，即middleLayer.__proto__ = Array.prototype
const middleLayer = Object.create(Array.prototype);
variationMethods.forEach((method) => {
  // 变异方法全部在middleLayer对象上实现一遍
  middleLayer[method] = function (...args) {
    // 实际执行的还是Array.prototype对象上的方法
    const result = tmpArrayPrototype[method].apply(this, args);
    console.log(`拦截到了${method}方法的执行`);
    return result;
  };
});

var arr = [];
arr.__proto__ = middleLayer;
arr.push(1);
console.log(arr);
// 但有些浏览器不支持 __proto__，所以就得另想一个办法去拦截，这次我们直接在实例上添加方法

const arr = [];
const arrayKeys = Object.getOwnPropertyNames(middleLayer);

arrayKeys.forEach((method) => {
  arr[method] = middleLayer[method];
});

// 但是这样有一个问题，就是在实例上添加的方法是可以被枚举出来的，
// 这和原来的方法表现不一致，所以我们可以通过Object.defineProperty来定义相关方法

const arr = [];
const arrayKeys = Object.getOwnPropertyNames(middleLayer);
arrayKeys.forEach((method) => {
  Object.defineProperty(arr, method, {
    enumerable: false,
    writable: true,
    configurable: true,
    value: middleLayer[method],
  });
});
